package models

import (
	"bigdevops/src/config"        // 引入自定义配置包
	"github.com/casbin/casbin/v2" // 引入 Casbin 权限管理包
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3" // 引入 Casbin 的 Gorm 适配器
	_ "github.com/go-sql-driver/mysql"              // 引入 MySQL 驱动
	"go.uber.org/zap"                               // 引入 zap 日志包
	"gorm.io/driver/mysql"                          // 引入 Gorm 的 MySQL 驱动
	"gorm.io/gorm"                                  // 引入 Gorm ORM 包
	"gorm.io/gorm/logger"                           // 引入 Gorm 日志包
	"time"                                          // 引入 time 包
)

var (
	Db             *gorm.DB         // Gorm 数据库实例
	casbinEnforcer *casbin.Enforcer // Casbin Enforcer 实例
)

// InitDb 初始化数据库连接
func InitDb(dsn string) error {
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		//Logger: logger.Default.LogMode(logger.Info), // 启用详细日志模式
		Logger: logger.Default.LogMode(logger.Silent), // 启用静默日志模式
	})
	if err != nil {
		return err
	}
	Db = db
	// 设置数据库连接池最大连接数
	dba, _ := Db.DB()
	dba.SetMaxOpenConns(10000)
	return nil
}

// InitCasbin 初始化 Casbin 权限管理
func InitCasbin(sc *config.ServerConfig) error {
	// 使用 Gorm 适配器初始化 Casbin
	a, err := gormadapter.NewAdapterByDB(Db)
	if err != nil {
		sc.Logger.Error("初始化 Casbin 数据库错误", zap.Error(err))
		return err
	}

	// 定义 Casbin 模型
	modelText := `
	[request_definition]
	r = sub, obj, act
	
	[policy_definition]
	p = sub, obj, act
	
	[role_definition]
	g = _, _
	
	[policy_effect]
	e = some(where (p.eft == allow))
	
	[matchers]
	m = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act
    `
	// 从字符串加载 Casbin 模型
	m, err := model.NewModelFromString(modelText)
	if err != nil {
		sc.Logger.Error("Casbin 字符串加载模型失败!", zap.Error(err))
		return err
	}

	// 创建 Casbin Enforcer 实例
	casbinEnforcer, err = casbin.NewEnforcer(m, a)
	if err != nil {
		sc.Logger.Error("Casbin 创建 Enforcer 失败!", zap.Error(err))
		return err
	}
	return nil
}

// MigrateTable 自动迁移数据库表
func MigrateTable() error {
	return Db.AutoMigrate(
		// 底座相关模型
		&User{},
		&Role{},
		&Menu{},
		&Api{},

		// 服务树和 CMDB 模型
		&StreeNode{},
		&ResourceEcs{},
		&ResourceElb{},
		&ResourceRds{},

		// 工单相关模型
		&Process{},
		&FlowNode{},
		&FormDesign{},
		&WorkOrderTemplate{},
		&WorkOrderInstance{},

		// 任务执行相关模型
		&JobScript{},
		&JobTask{},
		&JobResult{},

		// Prometheus 监控相关模型
		&MonitorScrapePool{},
		&MonitorScrapeJob{},
		&MonitorAlertmanagerPool{},
		&MonitorSendGroup{},
		&MonitorAlertRule{},
		&MonitorAlertEvent{},
		&MonitorRecordRule{},

		&MonitorOndutyGroup{},   // 值班相关模型
		&MonitorOndutyHistory{}, // 值班历史记录模型
		&MonitorOndutyChange{},  // 值班变更记录模型

		// K8s 相关模型
		&K8sCluster{},
		&K8sYamlTemplate{},
		&K8sYamlTask{},
		&K8sProject{},
		&K8sApp{},
		&K8sInstance{},
		&K8sCronjob{},

		// CI/CD 相关模型
		&CicdDeployItem{},
		&CicdWorkOrder{},
		&CicdDeployStageStatus{},
	)
}

// InsertBasicDbData 插入基础数据库数据
// - 默认注入的数据只有底座和服务树：因为 K8s、CI/CD、Prometheus 每个人不一样，注入的过程会报错和比较慢所以注释了
func InsertBasicDbData(sc *config.ServerConfig) {
	start := time.Now() // 记录开始时间

	MockBasicData(sc) // 模拟基础数据
	sc.Logger.Info("计算 mock 时间", zap.Any("模块", "[01 底座]"), zap.Duration("耗时", time.Since(start)))

	/*	MockCmdbTree(sc) // 模拟 CMDB 服务树数据
		sc.Logger.Info("计算 mock 时间", zap.Any("模块", "[02 服务树]"), zap.Duration("耗时", time.Since(start)))

		MockWorkOrder(sc) // 模拟工单数据
		sc.Logger.Info("计算 mock 时间", zap.Any("模块", "[03 工单]"), zap.Duration("耗时", time.Since(start)))

		MockJobExec(sc) // 模拟任务执行数据
		sc.Logger.Info("计算 mock 时间", zap.Any("模块", "[04 任务执行]"), zap.Duration("耗时", time.Since(start)))

		MockMonitor(sc) // 模拟监控数据
		sc.Logger.Info("计算 mock 时间", zap.Any("模块", "[05 Prometheus]"), zap.Duration("耗时", time.Since(start)))

		MockK8s(sc) // 模拟 K8s 数据
		sc.Logger.Info("计算 mock 时间", zap.Any("模块", "[06 K8s]"), zap.Duration("耗时", time.Since(start)))

		MockCicd(sc) // 模拟 CI/CD 数据
		sc.Logger.Info("计算 mock 时间", zap.Any("模块", "[07 CI/CD]"), zap.Duration("耗时", time.Since(start)))*/
}
